//! 传感器工具模块
//! 
//! 提供传感器相关的工具函数

use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use crate::objects::bar::RawBar;
use super::event::{Event, EventType, EventLevel};
use super::feature::{Feature, FeatureType};

/// 传感器工具结构体
pub struct SensorUtils {
    /// 工具配置
    config: HashMap<String, serde_json::Value>,
}

impl SensorUtils {
    /// 创建新的传感器工具
    pub fn new(config: HashMap<String, serde_json::Value>) -> Self {
        Self { config }
    }
    
    /// 计算移动平均
    pub fn calculate_ma(&self, prices: &[f64], period: usize) -> Vec<f64> {
        if prices.len() < period {
            return vec![];
        }
        
        let mut result = Vec::new();
        for i in period - 1..prices.len() {
            let sum: f64 = prices[i - period + 1..=i].iter().sum();
            result.push(sum / period as f64);
        }
        
        result
    }
    
    /// 计算标准差
    pub fn calculate_std(&self, values: &[f64]) -> f64 {
        if values.is_empty() {
            return 0.0;
        }
        
        let mean = values.iter().sum::<f64>() / values.len() as f64;
        let variance = values.iter()
            .map(|v| (v - mean).powi(2))
            .sum::<f64>() / values.len() as f64;
        
        variance.sqrt()
    }
    
    /// 计算Z分数
    pub fn calculate_z_score(&self, value: f64, mean: f64, std: f64) -> f64 {
        if std == 0.0 {
            return 0.0;
        }
        
        (value - mean) / std
    }
    
    /// 检测异常值
    pub fn detect_outliers(&self, values: &[f64], threshold: f64) -> Vec<usize> {
        if values.len() < 3 {
            return vec![];
        }
        
        let mean = values.iter().sum::<f64>() / values.len() as f64;
        let std = self.calculate_std(values);
        
        let mut outliers = Vec::new();
        for (i, &value) in values.iter().enumerate() {
            let z_score = self.calculate_z_score(value, mean, std);
            if z_score.abs() > threshold {
                outliers.push(i);
            }
        }
        
        outliers
    }
    
    /// 计算相关性
    pub fn calculate_correlation(&self, x: &[f64], y: &[f64]) -> f64 {
        if x.len() != y.len() || x.is_empty() {
            return 0.0;
        }
        
        let n = x.len() as f64;
        let sum_x: f64 = x.iter().sum();
        let sum_y: f64 = y.iter().sum();
        let sum_xy: f64 = x.iter().zip(y.iter()).map(|(a, b)| a * b).sum();
        let sum_x2: f64 = x.iter().map(|a| a * a).sum();
        let sum_y2: f64 = y.iter().map(|b| b * b).sum();
        
        let numerator = n * sum_xy - sum_x * sum_y;
        let denominator = ((n * sum_x2 - sum_x * sum_x) * (n * sum_y2 - sum_y * sum_y)).sqrt();
        
        if denominator == 0.0 {
            return 0.0;
        }
        
        numerator / denominator
    }
    
    /// 计算动量
    pub fn calculate_momentum(&self, prices: &[f64], period: usize) -> Vec<f64> {
        if prices.len() < period + 1 {
            return vec![];
        }
        
        let mut momentum = Vec::new();
        for i in period..prices.len() {
            let momentum_value = (prices[i] - prices[i - period]) / prices[i - period];
            momentum.push(momentum_value);
        }
        
        momentum
    }
    
    /// 计算相对强弱指数
    pub fn calculate_rsi(&self, prices: &[f64], period: usize) -> Vec<f64> {
        if prices.len() < period + 1 {
            return vec![];
        }
        
        let mut gains = Vec::new();
        let mut losses = Vec::new();
        
        // 计算价格变化
        for i in 1..prices.len() {
            let change = prices[i] - prices[i - 1];
            gains.push(change.max(0.0));
            losses.push((-change).max(0.0));
        }
        
        let mut rsi_values = Vec::new();
        
        // 计算初始平均增益和损失
        let avg_gain: f64 = gains[..period].iter().sum::<f64>() / period as f64;
        let avg_loss: f64 = losses[..period].iter().sum::<f64>() / period as f64;
        
        let mut prev_avg_gain = avg_gain;
        let mut prev_avg_loss = avg_loss;
        
        // 计算第一个RSI值
        if prev_avg_loss == 0.0 {
            rsi_values.push(100.0);
        } else {
            let rs = prev_avg_gain / prev_avg_loss;
            rsi_values.push(100.0 - (100.0 / (1.0 + rs)));
        }
        
        // 计算后续RSI值
        for i in period..gains.len() {
            let alpha = 1.0 / period as f64;
            prev_avg_gain = alpha * gains[i] + (1.0 - alpha) * prev_avg_gain;
            prev_avg_loss = alpha * losses[i] + (1.0 - alpha) * prev_avg_loss;
            
            if prev_avg_loss == 0.0 {
                rsi_values.push(100.0);
            } else {
                let rs = prev_avg_gain / prev_avg_loss;
                rsi_values.push(100.0 - (100.0 / (1.0 + rs)));
            }
        }
        
        rsi_values
    }
    
    /// 从K线数据创建事件
    pub fn create_event_from_bars(
        &self,
        bars: &[RawBar],
        event_type: EventType,
        level: EventLevel,
        description: &str,
    ) -> Option<Event> {
        if bars.is_empty() {
            return None;
        }
        
        let current_bar = &bars[bars.len() - 1];
        
        let event = Event::new(
            format!("sensor_event_{}", current_bar.dt.timestamp()),
            event_type,
            level,
            current_bar.dt,
            description.to_string(),
            current_bar.symbol.clone(),
        );
        
        Some(event)
    }
    
    /// 从K线数据创建特征
    pub fn create_feature_from_bars(
        &self,
        bars: &[RawBar],
        name: &str,
        feature_type: FeatureType,
        value: f64,
        description: &str,
    ) -> Option<Feature> {
        if bars.is_empty() {
            return None;
        }
        
        let current_bar = &bars[bars.len() - 1];
        
        let feature = Feature::new(
            name.to_string(),
            feature_type,
            value,
            current_bar.dt,
            description.to_string(),
            current_bar.symbol.clone(),
        );
        
        Some(feature)
    }
    
    /// 计算技术指标
    pub fn calculate_technical_indicators(&self, bars: &[RawBar]) -> HashMap<String, f64> {
        let mut indicators = HashMap::new();
        
        if bars.len() < 20 {
            return indicators;
        }
        
        let prices: Vec<f64> = bars.iter().map(|b| b.close).collect();
        let volumes: Vec<f64> = bars.iter().map(|b| b.vol).collect();
        
        // 计算SMA
        if let Some(sma) = self.calculate_ma(&prices, 20).last() {
            indicators.insert("SMA_20".to_string(), *sma);
        }
        
        // 计算RSI
        if let Some(rsi) = self.calculate_rsi(&prices, 14).last() {
            indicators.insert("RSI_14".to_string(), *rsi);
        }
        
        // 计算动量
        if let Some(momentum) = self.calculate_momentum(&prices, 10).last() {
            indicators.insert("MOMENTUM_10".to_string(), *momentum);
        }
        
        // 计算成交量平均值
        let avg_volume = volumes.iter().sum::<f64>() / volumes.len() as f64;
        indicators.insert("AVG_VOLUME".to_string(), avg_volume);
        
        indicators
    }
    
    /// 检测趋势
    pub fn detect_trend(&self, prices: &[f64], period: usize) -> String {
        if prices.len() < period * 2 {
            return "未知".to_string();
        }
        
        let recent_prices = &prices[prices.len() - period..];
        let previous_prices = &prices[prices.len() - period * 2..prices.len() - period];
        
        let recent_avg = recent_prices.iter().sum::<f64>() / recent_prices.len() as f64;
        let previous_avg = previous_prices.iter().sum::<f64>() / previous_prices.len() as f64;
        
        let change = (recent_avg - previous_avg) / previous_avg;
        
        if change > 0.02 {
            "上升".to_string()
        } else if change < -0.02 {
            "下降".to_string()
        } else {
            "横盘".to_string()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_calculate_ma() {
        let utils = SensorUtils::new(HashMap::new());
        let prices = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let ma = utils.calculate_ma(&prices, 3);
        
        assert_eq!(ma, vec![2.0, 3.0, 4.0]);
    }
    
    #[test]
    fn test_calculate_std() {
        let utils = SensorUtils::new(HashMap::new());
        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let std = utils.calculate_std(&values);
        
        assert!((std - 1.5811388300841898).abs() < 1e-10);
    }
    
    #[test]
    fn test_calculate_z_score() {
        let utils = SensorUtils::new(HashMap::new());
        let z_score = utils.calculate_z_score(5.0, 3.0, 1.0);
        
        assert_eq!(z_score, 2.0);
    }
    
    #[test]
    fn test_detect_outliers() {
        let utils = SensorUtils::new(HashMap::new());
        let values = vec![1.0, 2.0, 3.0, 100.0, 4.0, 5.0];
        let outliers = utils.detect_outliers(&values, 2.0);
        
        assert_eq!(outliers, vec![3]); // 100.0是异常值
    }
    
    #[test]
    fn test_calculate_correlation() {
        let utils = SensorUtils::new(HashMap::new());
        let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let y = vec![2.0, 4.0, 6.0, 8.0, 10.0];
        let correlation = utils.calculate_correlation(&x, &y);
        
        assert!((correlation - 1.0).abs() < 1e-10);
    }
    
    #[test]
    fn test_calculate_momentum() {
        let utils = SensorUtils::new(HashMap::new());
        let prices = vec![10.0, 11.0, 12.0, 13.0, 14.0];
        let momentum = utils.calculate_momentum(&prices, 2);
        
        assert_eq!(momentum, vec![0.2, 0.18181818181818182, 0.16666666666666666]);
    }
    
    #[test]
    fn test_calculate_rsi() {
        let utils = SensorUtils::new(HashMap::new());
        let prices = vec![44.0, 44.34, 44.09, 44.15, 43.61, 44.33, 44.34, 44.09, 44.15, 43.61];
        let rsi = utils.calculate_rsi(&prices, 3);
        
        assert!(!rsi.is_empty());
        assert!(rsi[0] >= 0.0 && rsi[0] <= 100.0);
    }
    
    #[test]
    fn test_detect_trend() {
        let utils = SensorUtils::new(HashMap::new());
        let prices = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
        let trend = utils.detect_trend(&prices, 3);
        
        assert_eq!(trend, "上升");
    }
    
    #[test]
    fn test_create_event_from_bars() {
        let utils = SensorUtils::new(HashMap::new());
        
        let bars = vec![
            RawBar {
                symbol: "000001.SZ".to_string(),
                dt: Utc::now(),
                open: 10.0,
                close: 11.0,
                high: 12.0,
                low: 9.0,
                vol: 1000.0,
                amount: 10000.0,
                cache: None,
            }
        ];
        
        let event = utils.create_event_from_bars(
            &bars,
            EventType::PriceBreak,
            EventLevel::High,
            "测试事件",
        );
        
        assert!(event.is_some());
        if let Some(event) = event {
            assert_eq!(event.event_type, EventType::PriceBreak);
            assert_eq!(event.level, EventLevel::High);
        }
    }
    
    #[test]
    fn test_create_feature_from_bars() {
        let utils = SensorUtils::new(HashMap::new());
        
        let bars = vec![
            RawBar {
                symbol: "000001.SZ".to_string(),
                dt: Utc::now(),
                open: 10.0,
                close: 11.0,
                high: 12.0,
                low: 9.0,
                vol: 1000.0,
                amount: 10000.0,
                cache: None,
            }
        ];
        
        let feature = utils.create_feature_from_bars(
            &bars,
            "测试特征",
            FeatureType::Price,
            0.1,
            "测试特征描述",
        );
        
        assert!(feature.is_some());
        if let Some(feature) = feature {
            assert_eq!(feature.name, "测试特征");
            assert_eq!(feature.feature_type, FeatureType::Price);
            assert_eq!(feature.value, 0.1);
        }
    }
} 